package com.nirvana.utils;

import com.nirvana.convert.CamelCaseConverter;
import com.nirvana.data.DaoGenerateContext;
import com.nirvana.data.DbFieldInfo;
import com.nirvana.generate.OrmEntityGenerator;
import com.nirvana.type.DaoOption;

import java.util.List;

/**
 * 实体代码生成
 */
public class EntityCodeUtil {
    public static String generateEntityCode() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        boolean canCacher = false;
        for (DbFieldInfo element : context.fields) {
            if (element.isFlag()) {
                canCacher = true;
                break;
            }
        }
        StringBuilder result = new StringBuilder();

        /* 所属包 */
        result.append("package ").append(CommonUtil.generateDaoEntityPackage()).append(";\n\n");

        /* 导入类 */
        result.append(generateImport()).append("\n");
        if (canCacher) {
            result.append("import com.nirvana.database.DataObject;\n");
            result.append("import com.nirvana.database.DataOption;\n\n");
        }

        /* Class 开头 */
        if (canCacher) {
            result.append("public class ").append(context.entityName).append(" extends DataObject \n{\n");
        } else {
            result.append("public class ").append(context.entityName).append("\n{\n");
        }

        result.append(Constructor(context.entityName));

        if (context.options.get(DaoOption.FULL_CONSTRUCTOR)) {
            result.append("""
                        public %s(%s) {
                            super(true);
                    %s
                        }
                    
                    """.formatted(
                    context.entityName,
                    getMethodParams(context.fields),
                    generatePropertiesInit(context.fields)
            ));
        }

        /* 各个私有属性 */
        result.append(generatePropertiesPrivate());

        /* Get Set 方法 */
        result.append(generateMethodGetterAndSetterPublic());

        /* Class 结尾 */
        result.append("}");

        return result.toString();
    }

    private static String generatePropertiesInit(List<DbFieldInfo> fields) {
        StringBuilder content = new StringBuilder();
        for (DbFieldInfo field : fields) {
            String propertyName = CamelCaseConverter.toCamelCase(field.getColumnName(), true);
            content.append("""
                            this.%s = %s;
                    """.formatted(propertyName, propertyName));
        }
        return content.toString().stripTrailing();
    }

    private static String getMethodParams(List<DbFieldInfo> fields) {
        List<String> list = fields.stream().map(info -> info.getJavaType() + " " + CamelCaseConverter.toCamelCase(info.getColumnName(), true)).toList();
        return String.join(", ", list);
    }

    /**
     * 应该只有 Date 需要另外导入, 其他都是默认包 java.lang...
     */
    private static String generateImport() {
        for (DbFieldInfo field : OrmEntityGenerator.context.fields) {
            if (field.getJavaType().equals("Date")) // 非完全匹配
            {
                return "import java.util.Date;\n";
            }
        }
        return "";
    }

    private static StringBuilder Constructor(String className) {
        StringBuilder result = new StringBuilder();
        result.append("\tpublic ").append(className).append("(boolean insert)").append("\n");
        result.append("\t{").append("\n");
        result.append("\t\t").append("super(insert);").append("\n");
        result.append("\t}").append("\n\n");

        result.append("\tpublic ").append(className).append("()").append("\n");
        result.append("\t{").append("\n");
        result.append("\t\t").append("super(false);").append("\n");
        result.append("\t}").append("\n\n");
        return result;


    }

    /**
     * 生成私有属性, 属性命名与表字段统一
     */
    private static StringBuilder generatePropertiesPrivate() {
        StringBuilder result = new StringBuilder();

        for (DbFieldInfo field : OrmEntityGenerator.context.fields) {
            // 加注释
            result.append(addComment(field.getComment()));
            result.append("\tprivate ");
            result.append(field.getJavaType()).append(" ").append(CommonUtil.toLowerName(field.getColumnName())).append(";\n");
            result.append("\n");
        }
        return result.append("\n");
    }

    /**
     * 生成公开的 setter 和 getter 方法
     */
    private static StringBuilder generateMethodGetterAndSetterPublic() {
        StringBuilder result = new StringBuilder();

        for (DbFieldInfo field : OrmEntityGenerator.context.fields) {
            // 加注释
            result.append(addComment(field.getComment()));

            result.append(makeGetter(CommonUtil.toLowerName(field.getColumnName()), field.getJavaType()));
            result.append("\n");

            // 加注释
            result.append(addComment(field.getComment()));

            result.append(makeSetter(CommonUtil.toLowerName(field.getColumnName()), field.getJavaType(), field.isFlag()));
            result.append("\n");

        }
        return result;

    }

    private static StringBuilder makeSetter(String var, String type, boolean flag) {
        StringBuilder result = new StringBuilder("\tpublic ");
        result.append("void" + " set").append(var.substring(0, 1).toUpperCase()).append(var.substring(1)).append("(").append(type).append(" ").append(var).append(")\n");
        result.append("\t{\n");
        if (flag) {
            if (type.equals("String") || type.equals("Date")) {
                result.append("\t\tif(").append(var).append(" != null && ! ").append(var).append(".equals(this.").append(var).append("))\n");
            } else {
                result.append("\t\tif(").append(var).append(" != this.").append(var).append(")\n");
            }

            result.append("\t\t{\n");
            result.append("\t\t\tthis.").append(var).append(" = ").append(var).append(";\n");
            result.append("\t\t\tsetOp(DataOption.UPDATE);\n");
            result.append("\t\t}\n");
        } else {
            result.append("\t\tthis.").append(var).append(" = ").append(var).append(";\n");
        }
        result.append("\t}\n");
        return result;
    }

    private static StringBuilder makeGetter(String var, String type) {
        StringBuilder result = new StringBuilder("\tpublic ");
        result.append(type).append(" get").append(CommonUtil.toUpperName(var)).append("()\n");
        result.append("\t{\n");
        result.append("\t\treturn ").append(var).append(";\n");
        result.append("\t}\n");
        return result;
    }

    /**
     * 添加字段注释
     */
    private static StringBuilder addComment(String value) {

        StringBuilder result = new StringBuilder();
        result.append("\t").append("/**").append("\n");
        result.append("\t").append(" * ").append(value).append("\n");
        result.append("\t").append(" */").append("\n");
        return result;
    }
}
